﻿namespace MoskvaFM
{
    using System;
    using System.Configuration;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;

    using Microsoft.WindowsAPICodePack.Taskbar;

    using MoskvaFM.Properties;

    using xLib;

    public partial class FormMain : Form
    {
        private const string ConfigFilesPath = "lists";

        private const int WH_KEYBOARD_LL = 13;

        private const int WM_KEYDOWN = 0x0100;

        private readonly bool isToolbarAllowed;

        private readonly ThumbnailToolBarButton thumbButtonNext;

        private readonly ThumbnailToolBarButton thumbButtonPrev;

        private readonly ThumbnailToolBarButton thumbButtonPause;

        private readonly bool minimizeToTray;

        private static readonly LowLevelKeyboardProc Proc = HookCallback;

        private static FormMain instance;

        private static IntPtr hookId = IntPtr.Zero;

        private bool isInitialized;

        private bool isPaused;

        public FormMain()
        {
            InitializeComponent();
            instance = this;
            minimizeToTray = ConfigurationManager.AppSettings["MinimizeToTray"] == "true";

            isToolbarAllowed = TaskbarManager.IsPlatformSupported;
            if (isToolbarAllowed)
            {
                thumbButtonNext = new ThumbnailToolBarButton(Resources.forward, "Next station");
                thumbButtonPrev = new ThumbnailToolBarButton(Resources.backward, "Previous station");
                thumbButtonPause = new ThumbnailToolBarButton(Resources.play, "Play/Pause");
                thumbButtonNext.Click += thumbButtonNext_Click;
                thumbButtonPrev.Click += thumbButtonPrev_Click;
                thumbButtonPause.Click += thumbButtonPause_Click;
            }
        }

        private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        private static IntPtr SetHook(LowLevelKeyboardProc proc)
        {
            using (var curProcess = Process.GetCurrentProcess())
            {
                using (var curModule = curProcess.MainModule)
                {
                    return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
                }
            }
        }

        private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
            {
                var vkCode = (Keys)Marshal.ReadInt32(lParam);
                switch (vkCode)
                {
                    case Keys.MediaNextTrack:
                        {
                            instance.SwitchToNextStation();
                            break;
                        }

                    case Keys.MediaPreviousTrack:
                        {
                            instance.SwitchToPrevStation();
                            break;
                        }

                    case Keys.MediaPlayPause:
                        {
                            instance.SwitchPlayPause();
                            break;
                        }
                }
            }

            return CallNextHookEx(hookId, nCode, wParam, lParam);
        }

        private void FormMain_Load(object sender, EventArgs e)
        {
            var configPath = Path.Combine(Application.StartupPath, ConfigFilesPath);
            if (!Directory.Exists(configPath))
            {
                MessageBox.Show("Не найдена папка " + ConfigFilesPath);
                Close();
                return;
            }

            try
            {
                var files = Directory.GetFiles(configPath, "*.txt", SearchOption.AllDirectories);
                var factory = new StationSourceFactory();
                foreach (var file in files)
                {
                    var fname = Path.GetFileName(file);
                    if (string.IsNullOrEmpty(fname))
                    {
                        continue;
                    }

                    var stationSource = factory.GetSource(fname);
                    if (stationSource == null)
                    {
                        continue;
                    }

                    var list = File.ReadAllLines(file);
                    foreach (var s in list.Select(str => str.Split(';')).Where(s => s.Length == 2))
                    {
                        listStationsList.Items.Add(new Station { ID = s[1].Trim(), Name = s[0].Trim(), StationSource = stationSource });
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                Close();
                return;
            }

            if (listStationsList.Items.Count == 0)
            {
                MessageBox.Show("Нет ни одной станции");
                Close();
                return;
            }

            AddThumbnailButtons();

            listStationsList.SelectedIndex = 0;
            SettingsDumper.Init(this);

            dtBroadcastDate.MaxDate = DateTime.Now.AddDays(1);
            PauseStation();
            isInitialized = true;
            if (ConfigurationManager.AppSettings["MediaHotKeysEnabled"] == "true")
            {
                hookId = SetHook(Proc);
            }
        }

        private void thumbButtonPause_Click(object sender, EventArgs e)
        {
            SwitchPlayPause();
        }

        private void thumbButtonPrev_Click(object sender, EventArgs e)
        {
            SwitchToPrevStation();
        }

        private void thumbButtonNext_Click(object sender, EventArgs e)
        {
            SwitchToNextStation();
        }

        private void listStationsList_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!isInitialized)
            {
                return;
            }

            PlayStation();
        }

        private void bPlayPause_Click(object sender, EventArgs e)
        {
            SwitchPlayPause();
        }

        private void SwitchToPrevStation()
        {
            if (listStationsList.SelectedIndex == 0)
            {
                listStationsList.SelectedIndex = listStationsList.Items.Count - 1;
                return;
            }

            listStationsList.SelectedIndex--;
        }

        private void SwitchToNextStation()
        {
            if (listStationsList.SelectedIndex == listStationsList.Items.Count - 1)
            {
                listStationsList.SelectedIndex = 0;
                return;
            }

            listStationsList.SelectedIndex++;
        }

        private void SwitchPlayPause()
        {
            if (isPaused)
            {
                PlayStation();
            }
            else
            {
                PauseStation();
            }
        }

        private void PauseStation()
        {
            if (WindowState != FormWindowState.Minimized)
            {
                if (isToolbarAllowed)
                {
                    thumbButtonPause.Icon = Resources.play;
                }

                Icon = Resources.paused;
            }

            isPaused = true;
            bPlayPause.Text = "Play";
            notifyIcon.Icon = Resources.paused;
            webBrowser1.DocumentText = "<table border=0 width=100% height=100%><tr><td><center><span style='font-family: Meiryo;font-size:40px'>Paused</td></tr></table>";
        }

        private void PlayStation()
        {
            var date = dtBroadcastDate.Value;
            var time = ((int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds).ToString();
            if (date != default(DateTime))
            {
                time = ((int)(date - new DateTime(1970, 1, 1)).TotalSeconds).ToString();
            }

            bPlayPause.Text = "Pause";

            if (WindowState != FormWindowState.Minimized)
            {
                if (isToolbarAllowed)
                {

                    thumbButtonPause.Icon = Resources.pause;
                }
            
                Icon = Resources.playing;
            }

            isPaused = false;
            var station = (Station)listStationsList.SelectedItem;
            var curStationName = string.Format("{0} - Moskva.FM", station.DisplayName);
            Text = curStationName;
            notifyIcon.Text = curStationName;
            notifyIcon.Icon = Resources.playing;
            webBrowser1.DocumentText = station.GetDocument(time);
        }

        private void btnSetDate_Click(object sender, EventArgs e)
        {
            PlayStation();
        }

        private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                WindowState = WindowState == FormWindowState.Minimized ? FormWindowState.Normal : FormWindowState.Minimized;
                if (WindowState != FormWindowState.Minimized)
                {
                    Activate();
                    ShowInTaskbar = true;
                    if (isPaused)
                    {
                        Icon = Resources.paused;
                        if (isToolbarAllowed)
                        {
                            thumbButtonPause.Icon = Resources.play;
                        }
                    } 
                    else
                    {
                        Icon = Resources.playing;
                        if (isToolbarAllowed)
                        {
                            thumbButtonPause.Icon = Resources.pause;
                        }
                    }
                }
            }
            else
            {
                SwitchPlayPause();
            }
        }

        private void FormMain_Resize(object sender, EventArgs e)
        {
            if (!minimizeToTray)
            {
                return;
            }

            var isRestored = !ShowInTaskbar && WindowState != FormWindowState.Minimized;
            ShowInTaskbar = WindowState != FormWindowState.Minimized;
            if (isRestored && ShowInTaskbar)
            {
                AddThumbnailButtons();
            }

            FormBorderStyle = !ShowInTaskbar ? FormBorderStyle.SizableToolWindow : FormBorderStyle.Sizable;
        }

        private void AddThumbnailButtons()
        {
            if (!isToolbarAllowed)
            {
                return;
            }

            TaskbarManager.Instance.ThumbnailToolBars.AddButtons(Handle, thumbButtonPrev, thumbButtonPause, thumbButtonNext);
        }

        private void ToolStripMenuItemExit_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void FormMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (hookId != IntPtr.Zero)
            {
                UnhookWindowsHookEx(hookId);
            }
        }
    }
}
